#!/usr/bin/env python3
"""
Main CLI Entry Point for Fortran Code Commentator

Professional command-line interface for automated Fortran code commenting.
Supports batch processing, configuration management, and various output formats.
"""

import sys
import os
import argparse
import logging
import json
from pathlib import Path
from typing import Dict, Any, List, Optional
from dotenv import load_dotenv

from ..__version__ import __version__, RELEASE_NOTES
from ..config.manager import ConfigManager, create_default_profiles
from ..core.system import CodeCommentarySystem


def setup_logging(level: str) -> None:
    """Setup logging configuration"""
    numeric_level = getattr(logging, level.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError(f'Invalid log level: {level}')
    
    logging.basicConfig(
        level=numeric_level,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            logging.StreamHandler(sys.stdout),
            logging.FileHandler('fortran-commentator.log')
        ]
    )


def create_parser() -> argparse.ArgumentParser:
    """Create the argument parser"""
    parser = argparse.ArgumentParser(
        prog='fortran-commentator',
        description='Automated code commenting system for Fortran codebases',
        epilog=f'Version {__version__} - Professional Fortran documentation tool'
    )
    
    # Version information
    parser.add_argument(
        '--version', '-V',
        action='version',
        version=f'fortran-commentator {__version__}'
    )
    
    # Subcommands
    subparsers = parser.add_subparsers(
        dest='command',
        help='Available commands',
        metavar='{process,config,validate,init}'
    )
    
    # Process command (main functionality)
    process_parser = subparsers.add_parser(
        'process',
        help='Process Fortran files and add comments'
    )
    _add_process_arguments(process_parser)
    
    # Config command
    config_parser = subparsers.add_parser(
        'config', 
        help='Manage configuration settings'
    )
    _add_config_arguments(config_parser)
    
    # Validate command
    validate_parser = subparsers.add_parser(
        'validate',
        help='Validate Fortran files and configuration'
    )
    _add_validate_arguments(validate_parser)
    
    # Init command 
    init_parser = subparsers.add_parser(
        'init',
        help='Initialize project with default configuration'
    )
    _add_init_arguments(init_parser)
    
    return parser


def _add_process_arguments(parser: argparse.ArgumentParser) -> None:
    """Add arguments for the process command"""
    
    # Optional source path (defaults to WORK_DIR from .env)
    parser.add_argument(
        'source_path',
        nargs='?',
        default=os.getenv('WORK_DIR', '.'),
        help='Path to Fortran source directory or file (default: WORK_DIR from .env or current directory)'
    )
    
    # Optional processing arguments
    parser.add_argument(
        '--output', '-o',
        help='Output directory for processed files (default: in-place editing)'
    )
    
    parser.add_argument(
        '--workers', '-w',
        type=int,
        default=int(os.getenv('DEFAULT_WORKERS', '4')),
        help=f'Number of parallel workers (default: {os.getenv("DEFAULT_WORKERS", "4")})'
    )
    
    parser.add_argument(
        '--max-lines',
        type=int,
        default=int(os.getenv('DEFAULT_MAX_LINES', '1500')),
        help=f'Skip files larger than this many lines (default: {os.getenv("DEFAULT_MAX_LINES", "1500")})'
    )
    
    # LLM configuration
    parser.add_argument(
        '--llm-url',
        default=os.getenv('OLLAMA_HOST', 'http://60.245.128.27:11434'),
        help='LLM server URL (default: http://60.245.128.27:11434)'
    )
    
    parser.add_argument(
        '--llm-model', 
        default=os.getenv('OLLAMA_MODEL', 'hopephoto/qwen3-30b-a3b-instruct_q8:latest'),
        help='LLM model name (default: hopephoto/qwen3-30b-a3b-instruct_q8:latest)'
    )
    
    parser.add_argument(
        '--fast',
        action='store_true',
        help='Use Dashscope API (qwen3-30b-a3b-instruct-2507) for faster processing instead of Ollama'
    )
    
    parser.add_argument(
        '--fast-only',
        action='store_true',
        help='Use ONLY Dashscope API without fallback to Ollama (fails if Dashscope unavailable)'
    )
    
    # File filtering
    parser.add_argument(
        '--include',
        action='append',
        help='File patterns to include (can use multiple times)'
    )
    
    parser.add_argument(
        '--exclude',
        action='append', 
        help='File patterns to exclude (can use multiple times)'
    )
    
    parser.add_argument(
        '--classification',
        choices=['auto', 'background_grid', 'core_analysis', 'io_interface', 'observation_processing', 'utilities'],
        default=os.getenv('DEFAULT_CLASSIFICATION', 'auto'),
        help=f'Force specific code classification (default: {os.getenv("DEFAULT_CLASSIFICATION", "auto")})'
    )
    
    # Processing options
    parser.add_argument(
        '--dry-run',
        action='store_true',
        help='Show what would be processed without making changes'
    )
    
    parser.add_argument(
        '--backup/--no-backup',
        default=True,
        help='Create backup files before modification (default: enabled)'
    )
    
    parser.add_argument(
        '--retry',
        action='store_true',
        help='Reprocess files that have already been processed (ignores processing cache)'
    )
    
    parser.add_argument(
        '--compare',
        action='store_true',
        help='Compare line count changes between original and commented files (no processing)'
    )
    
    parser.add_argument(
        '--validate-syntax',
        action='store_true',
        help='Validate Fortran syntax after adding comments'
    )
    
    parser.add_argument(
        '--comment-style',
        choices=['doxygen', 'sphinx', 'custom'],
        default='doxygen',
        help='Comment style to use (default: doxygen)'
    )
    
    # Progress and output
    parser.add_argument(
        '--quiet', '-q',
        action='store_true',
        help='Suppress progress output'
    )
    
    parser.add_argument(
        '--verbose', '-v',
        action='count',
        default=0,
        help='Increase verbosity (-v, -vv, -vvv)'
    )
    
    parser.add_argument(
        '--progress-format',
        choices=['text', 'json', 'none'],
        default='text',
        help='Progress report format (default: text)'
    )
    
    parser.add_argument(
        '--report',
        help='Save processing report to file'
    )


def _add_config_arguments(parser: argparse.ArgumentParser) -> None:
    """Add arguments for the config command"""
    config_subparsers = parser.add_subparsers(
        dest='config_action',
        help='Configuration actions'
    )
    
    # Show config
    show_parser = config_subparsers.add_parser('show', help='Show current configuration')
    show_parser.add_argument('--format', choices=['yaml', 'json'], default='yaml')
    
    # Set config values
    set_parser = config_subparsers.add_parser('set', help='Set configuration values')
    set_parser.add_argument('key', help='Configuration key')
    set_parser.add_argument('value', help='Configuration value')
    
    # Validate config
    validate_parser = config_subparsers.add_parser('validate', help='Validate configuration')
    
    # Create profile
    profile_parser = config_subparsers.add_parser('profile', help='Manage configuration profiles')
    profile_parser.add_argument('profile_action', choices=['create', 'load', 'list'])
    profile_parser.add_argument('profile_name', nargs='?', help='Profile name')


def _add_validate_arguments(parser: argparse.ArgumentParser) -> None:
    """Add arguments for the validate command"""
    parser.add_argument(
        'path',
        help='Path to validate (file or directory)'
    )
    
    parser.add_argument(
        '--check-syntax',
        action='store_true',
        help='Check Fortran syntax'
    )
    
    parser.add_argument(
        '--check-style',
        action='store_true',
        help='Check code style compliance'
    )
    
    parser.add_argument(
        '--output-format',
        choices=['text', 'json'],
        default='text',
        help='Output format (default: text)'
    )


def _add_init_arguments(parser: argparse.ArgumentParser) -> None:
    """Add arguments for the init command"""
    parser.add_argument(
        'project_path',
        nargs='?',
        default='.',
        help='Project directory to initialize (default: current directory)'
    )
    
    parser.add_argument(
        '--profile',
        choices=['development', 'production', 'custom'],
        default='development',
        help='Configuration profile to use (default: development)'
    )
    
    parser.add_argument(
        '--force',
        action='store_true',
        help='Overwrite existing configuration files'
    )


def cmd_process(args: argparse.Namespace, config_manager: ConfigManager) -> int:
    """Handle the process command"""
    try:
        # Update configuration with command line arguments
        config_manager.update_config(
            max_workers=args.workers,
            max_file_lines=args.max_lines,
            llm_url=args.llm_url,
            llm_model=args.llm_model,
            backup_enabled=getattr(args, 'backup', True),
            validate_syntax=args.validate_syntax,
            comment_style=args.comment_style,
            retry_processed=getattr(args, 'retry', False),
            target_classification=getattr(args, 'classification', 'auto')
        )
        
        # Validate configuration
        validation = config_manager.validate_config()
        if not validation['valid']:
            print(f"Configuration validation failed:")
            for error in validation['errors']:
                print(f"  Error: {error}")
            return 1
        
        # Initialize commentary system
        use_fast = getattr(args, 'fast', False) or getattr(args, 'fast_only', False)
        fast_only = getattr(args, 'fast_only', False)
        
        system = CodeCommentarySystem(
            source_path=args.source_path,
            config=config_manager.get_config(),
            use_fast=use_fast,
            fast_only=fast_only
        )
        
        if args.dry_run:
            print("DRY RUN - No files will be modified")
            files = system.discover_files()
            tasks, task_stats = system.create_processing_tasks(files)
            print(f"Would process {len(tasks)} files:")
            for task in tasks[:10]:  # Show first 10
                print(f"  - {task.file_path} ({task.classification})")
            if len(tasks) > 10:
                print(f"  ... and {len(tasks) - 10} more files")
            print(f"\nClassification distribution: {task_stats['task_creation']['classification_distribution']}")
            return 0
        
        if getattr(args, 'compare', False):
            print("COMPARE MODE - Analyzing line count changes")
            return system.compare_line_counts()
        
        # Process files
        print(f"Processing Fortran files in: {args.source_path}")
        results = system.process_files()
        
        # Print results summary
        print(f"\nProcessing completed:")
        print(f"  Successful: {len(results.successful_files)}")
        print(f"  Failed: {len(results.failed_files)}")
        print(f"  Total time: {results.processing_time:.2f}s")
        
        # Save report if requested
        if args.report:
            report_data = {
                "successful_files": results.successful_files,
                "failed_files": results.failed_files,
                "statistics": results.statistics,
                "processing_time": results.processing_time
            }
            
            with open(args.report, 'w') as f:
                json.dump(report_data, f, indent=2)
            print(f"Report saved to: {args.report}")
        
        return 0 if len(results.failed_files) == 0 else 1
        
    except Exception as e:
        print(f"Error during processing: {e}")
        return 1


def cmd_config(args: argparse.Namespace, config_manager: ConfigManager) -> int:
    """Handle the config command"""
    try:
        if args.config_action == 'show':
            config_dict = config_manager._config_to_dict()
            if args.format == 'json':
                print(json.dumps(config_dict, indent=2))
            else:
                import yaml
                print(yaml.dump(config_dict, default_flow_style=False))
        
        elif args.config_action == 'set':
            config_manager.update_config(**{args.key: args.value})
            print(f"Set {args.key} = {args.value}")
        
        elif args.config_action == 'validate':
            validation = config_manager.validate_config()
            if validation['valid']:
                print("Configuration is valid")
            else:
                print("Configuration validation failed:")
                for error in validation['errors']:
                    print(f"  Error: {error}")
                for warning in validation['warnings']:
                    print(f"  Warning: {warning}")
                return 1
        
        elif args.config_action == 'profile':
            if args.profile_action == 'list':
                profiles = config_manager.list_profiles()
                print("Available profiles:")
                for profile in profiles:
                    print(f"  - {profile}")
            
            elif args.profile_action == 'load' and args.profile_name:
                config_manager.load_profile(args.profile_name)
                print(f"Loaded profile: {args.profile_name}")
        
        return 0
    
    except Exception as e:
        print(f"Configuration error: {e}")
        return 1


def cmd_validate(args: argparse.Namespace) -> int:
    """Handle the validate command"""
    # Implementation would validate Fortran files
    print(f"Validating: {args.path}")
    print("Validation feature coming soon!")
    return 0


def cmd_init(args: argparse.Namespace) -> int:
    """Handle the init command"""
    project_path = Path(args.project_path)
    
    try:
        # Create project structure
        config_dir = project_path / ".fortran-commentator"
        config_dir.mkdir(exist_ok=True)
        
        # Create default configuration
        config_manager = ConfigManager()
        create_default_profiles(config_manager)
        
        if args.profile in config_manager.list_profiles():
            config_manager.load_profile(args.profile)
        
        # Save configuration
        config_file = config_dir / "config.yaml"
        if config_file.exists() and not args.force:
            print(f"Configuration already exists: {config_file}")
            print("Use --force to overwrite")
            return 1
        
        config_manager.save_config(config_file)
        
        print(f"Initialized Fortran Code Commentator project in: {project_path}")
        print(f"Configuration saved to: {config_file}")
        print(f"Profile used: {args.profile}")
        
        return 0
        
    except Exception as e:
        print(f"Initialization error: {e}")
        return 1


def main() -> int:
    """Main CLI entry point"""
    load_dotenv()
    parser = create_parser()
    
    # Show help if no arguments provided
    if len(sys.argv) == 1:
        parser.print_help()
        return 1
    
    # If first argument is not a subcommand, default to 'process'
    if len(sys.argv) > 1 and sys.argv[1] not in ['process', 'config', 'validate', 'init']:
        # Insert 'process' as the first argument
        sys.argv.insert(1, 'process')
    
    args = parser.parse_args()
    
    # Setup logging based on verbosity
    if hasattr(args, 'quiet') and args.quiet:
        log_level = 'ERROR'
    elif hasattr(args, 'verbose'):
        if args.verbose >= 2:
            log_level = 'DEBUG'
        elif args.verbose >= 1:
            log_level = 'INFO'
        else:
            log_level = 'WARNING'
    else:
        log_level = 'INFO'
    
    setup_logging(log_level)
    
    # Handle commands
    if args.command == 'process':
        config_manager = ConfigManager()
        return cmd_process(args, config_manager)
    
    elif args.command == 'config':
        config_manager = ConfigManager()
        create_default_profiles(config_manager)
        return cmd_config(args, config_manager)
    
    elif args.command == 'validate':
        return cmd_validate(args)
    
    elif args.command == 'init':
        return cmd_init(args)
    
    else:
        parser.print_help()
        return 1


if __name__ == '__main__':
    sys.exit(main())